import dash
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
from dash import dcc, html
import plotly.express as px
import pandas as pd
# Load Data
df = pd.read_csv("https://raw.githubusercontent.com/plotly/Figure-Friday/refs/heads/main/2025/week-8/Dallas_Animal_Shelter_Data_Fiscal_Year_Jan_2024.csv")
df["Intake_Time"] = pd.to_datetime(df["Intake_Time"]).dt.hour
df["Intake_Date"] = pd.to_datetime(df['Intake_Date'])
df["Outcome_Date"] = pd.to_datetime(df['Outcome_Date'])
df["Animal_Stay_Days"] = (df["Outcome_Date"] - df["Intake_Date"]).dt.days
# Initialize Dash app with Bootstrap theme
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.SKETCHY])
# Custom color palette (teal/blue-green tones)
custom_colors = ["#17becf", "#1f77b4", "#2ca02c", "#ff7f0e", "#d62728"]
# Layout with KPIs
app.layout = dbc.Container([
dbc.Row([dbc.Col(html.H1("Analytics Dashboard of Dallas Animal Shelter", className="text-center text-light"), width=12)],
className="my-2 bg-primary p-2"),
dbc.Row([dbc.Col(html.Br(), width=12)]),
# KPI Cards Row
dbc.Row([
dbc.Col(dbc.Card(
dbc.CardBody([
html.H4("Total Animals", className="card-title"),
html.H5(id="total-animals", className="card-text", style={"color": "black"})
]),
color="white", outline=True, style={"border-radius": "15px"}
), width=4),
dbc.Col(dbc.Card(
dbc.CardBody([
html.H4("Average Stay Duration", className="card-title"),
html.H5(id="avg-stay", className="card-text", style={"color": "black"})
]),
color="white", outline=True, style={"border-radius": "15px"}
), width=4),
dbc.Col(dbc.Card(
dbc.CardBody([
html.H4("Unique Breeds", className="card-title"),
html.H5(id="unique-breeds", className="card-text", style={"color": "black"})
]),
color="white", outline=True, style={"border-radius": "15px"}
), width=4)
], className="mb-4"),
# Dropdown for animal type filter
dbc.Row([
dbc.Col(dcc.Dropdown(
id='animal-type',
clearable=False,
value="ALL",
options=[{'label': x, 'value': x} for x in ['ALL'] + df["Animal_Type"].unique().tolist()],
className="animal-type-dropdown", style={"border-radius": "15px"}
), width=4)
], className="mb-4"),
# Graphs in 2 columns
dbc.Row([
dbc.Col(html.Div(dcc.Graph(id='histogram', style={"border-radius": "15px", "overflow": "hidden"})), width=6),
dbc.Col(html.Div(dcc.Graph(id='ecdf', style={"border-radius": "15px", "overflow": "hidden"})), width=6)
]),
html.Br(),
# Graphs in 3 columns
dbc.Row([
dbc.Col(html.Div(dcc.Graph(id='pie', style={"border-radius": "15px", "overflow": "hidden"})), width=4),
dbc.Col(html.Div(dcc.Graph(id='strip-chart', style={"border-radius": "15px", "overflow": "hidden"})), width=4),
dbc.Col(html.Div(dcc.Graph(id='sunburst', style={"border-radius": "15px", "overflow": "hidden"})), width=4)
])
], fluid=True, style={"max-width": "1400px", "margin": "auto"})
# Callbacks for updating graphs and KPIs
@app.callback(
[Output("pie", "figure"),
Output("strip-chart", "figure"),
Output("sunburst", "figure"),
Output("ecdf", "figure"),
Output("histogram", "figure"),
Output("total-animals", "children"),
Output("avg-stay", "children"),
Output("unique-breeds", "children")],
[Input("animal-type", "value")]
)
def update_graphs_and_kpis(animal_chosen):
if animal_chosen != 'ALL':
df_filtered = df[df["Animal_Type"] == animal_chosen]
else:
df_filtered = df
# Update KPIs
total_animals = f"{df_filtered.shape[0]:,}"
avg_stay = f"{df_filtered['Animal_Stay_Days'].mean():.2f} days"
unique_breeds = f"{df_filtered['Animal_Breed'].nunique():,}"
# Histogram (single color)
fig_hist = px.histogram(df_filtered,
x="Animal_Breed",
title="Animal Count by Breed",
color="Animal_Breed",
color_discrete_sequence=["#17becf"], # Single color for the histogram
category_orders={"Animal_Breed": df_filtered["Animal_Breed"].unique().tolist()})
fig_hist.update_layout(plot_bgcolor='white', paper_bgcolor='white', showlegend=False)
# Pie chart
fig_pie = px.pie(df_filtered, names="Animal_Type", title="Animal Type", hole=0.6,
color_discrete_sequence=custom_colors)
fig_pie.update_layout(plot_bgcolor='white', paper_bgcolor='white', showlegend=True)
# Strip chart
fig_strip = px.strip(df_filtered, x="Animal_Stay_Days", y="Intake_Type", title="Stay Duration by Intake Type",
color_discrete_sequence=["#17becf"])
fig_strip.update_layout(plot_bgcolor='white', paper_bgcolor='white', showlegend=False)
# Sunburst chart
fig_sunburst = px.sunburst(df_filtered.dropna(subset=['Chip_Status']), path=["Animal_Type", "Intake_Type", "Chip_Status"],
title="Animal Intake and Chip Status",
color_discrete_sequence=custom_colors)
fig_sunburst.update_layout(plot_bgcolor='white', paper_bgcolor='white', showlegend=False)
# ECDF chart
fig_ecdf = px.ecdf(df_filtered, x="Animal_Stay_Days", color="Animal_Type", title="ECDF of Animal Stay Days",
color_discrete_sequence=custom_colors)
fig_ecdf.update_layout(plot_bgcolor='white', paper_bgcolor='white', showlegend=True)
fig_ecdf.update_traces(line=dict(width=3))
return fig_pie, fig_strip, fig_sunburst, fig_ecdf, fig_hist, total_animals, avg_stay, unique_breeds
if __name__ == '__main__':
app.run_server(debug=True)